home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 081 / upl.arc / UPL_100.DOC < prev    next >
Encoding:
Text File  |  1987-03-08  |  39.4 KB  |  1,005 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.                                      U P L
  21.  
  22.                             User Processing Language
  23.                             for Fido and Opus Sysops
  24.  
  25.  
  26.                             Version 1.00  --  3-8-87
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.                                 By Rick Huebner
  41.                            FidoNet/Matrix node 14/614
  42.                       402-291-8053, 3/12/2400 bps, 24 hrs.
  43.  
  44.  
  45.                           Copyright 1987 Rick Huebner
  46.                (Released for non-commercial use and distribution)
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.                                Table of Contents
  55.                                -----------------
  56.  
  57.             0.0   Legal notices and other crud to get over with ASAP
  58.             0.1     Distribution Rights.
  59.             0.2     Warranty.
  60.             0.3     Social Commentary.
  61.  
  62.             1.0   Overview/Introduction
  63.             1.1     What it is (bro').
  64.             1.2     Warnings, caveats, CYA.
  65.             1.3     Theory of Operation.
  66.  
  67.             2.0   Language Syntax
  68.             2.1     Invocation.
  69.             2.2     Command File Format.
  70.  
  71.             3.0   Language Components
  72.             3.1     Constants.
  73.             3.2     Variables.
  74.             3.3     Expressions.
  75.             3.4     Commands.
  76.  
  77.             4.0   Programming Considerations
  78.             4.1     Limitations.
  79.             4.2     Efficiency considerations.
  80.  
  81.             5.0   Postscript
  82.             5.1     Future Enhancements.
  83.             5.2     Bug Reports, etc.
  84.  
  85.  
  86.  
  87.  
  88. 0.0   Legal notices and other crud to get over with ASAP
  89. --------------------------------------------------------
  90.  
  91. 0.1   Distribution Rights.
  92.  
  93.    You are hereby granted a limited license to use UPL in any way you see fit,
  94. and to distribute it in any way you wish, so long as you don't charge more than
  95. $5 for it, said money intended to defray distribution costs.  If I catch you
  96. selling my software for profit, I'll say very nasty things about you on every
  97. network I have access to, attempt to start a boycott, and generally be as
  98. snotty about it as I can.  And if you're actually making any real money from
  99. this, I'll sue you for every penney of it.  So there.
  100.  
  101.    Also, I'd like to ask that patched or modified copies of this program not be
  102. distributed.  That's why I'm not giving out the source code... I hate it when
  103. 97 parallell versions of a popular program hit the phone lines.  I wouldn't
  104. want that to happen to UPL, if it were to become popular, so I'm going to
  105. maintain central control of the code.  Besides, this saves me the trouble of
  106. properly commenting my software.
  107.  
  108.  
  109. 0.2   Warranty.
  110.  
  111.    There isn't one.  This is a gift, not a commercial product; you have no
  112. legal recourse whatsoever. If it doesn't work, tough.  If it makes your hard
  113. disk into a neutron bomb, tough (although I would appreciate being informed).
  114. Now that that's out of the way, I'll promise that I did test this stuff pretty
  115. thoroughly before sending it out with my name on it, and that it works great
  116. for me.  But you know as well as I do that no program of this complexity is
  117. ever really bug-free, especially on version 1.00.  All I can do is try to fix
  118. 'em as I'm told about 'em, so please tell me about 'em. For your own safety,
  119. back up your USER.BBS file and test all programs before installing them
  120. operationally.  Lead shielding is optional.
  121.  
  122.  
  123. 0.3   Social Commentary.
  124.  
  125.    This program is a contribution on my part to the Fido/Opus community.  It's
  126. my way of paying back a little of the work of all those other utility writers
  127. whose programs make this such an enjoyable hobby.  In my humble (and totally
  128. unsolicited) opinion, if more people remembered their debt to the public domain
  129. and reimbursed it in kind, we'd all have a lot more fun.  Do Shareware authors
  130. generally make enough money to pay the Shareware fees for the software which
  131. they themselves use?  Can you say "vicious circle?"  I thought you could.
  132.  
  133.  
  134.  
  135.  
  136. 1.0   Overview/Introduction
  137. ---------------------------
  138.  
  139. 1.1   What it is (bro').
  140.  
  141.    UPL (User Processing Language) is an interpreted language specifically
  142. designed to help Fido and Opus sysops maintain their USER.BBS user data files.
  143. With it, you can do almost anything that you might ever want to your user data.
  144. You can change any piece of data for any user or group of users, generate all
  145. kinds of reports, automatically upgrade or downgrade user privileges according
  146. to your own wierd criteria, generate Opus custom welcome messages, and more.
  147. You want to purge all users who've called a prime number of times, use nulls,
  148. and have dared to look into message area 2?  No sweat.  On a more practical
  149. side, you want to automatically upgrade the privs of good upload contributors?
  150. Or generate nastygrams to download leeches?  Or fix people's message read
  151. counters after you've rearranged your message areas?  Also no sweat.
  152.  
  153.  
  154.    UPL features:
  155.  
  156.    *  Predefined variables for access to every part of a Fido or Opus USER.BBS
  157.       data record
  158.  
  159.    *  Special variables for things like upload/download ratio, number of days
  160.       since last call, command line arguments, etc.
  161.  
  162.    *  Predefined constants for standard privilege levels, help levels, etc.
  163.  
  164.    *  User-defined variables (for loop counters, doing computations, etc.)
  165.  
  166.    *  4-function math operations (ADD, SUB, MUL, DIV, MOD, no etc.)
  167.  
  168.    *  Nested IF-THEN-ELSE blocks
  169.  
  170.    *  GOTOs and labels
  171.  
  172.    *  Full trace mode for debugging
  173.  
  174.    *  'Intelligent' support of Opus's .GBS/.BBS files and custom welcomes
  175.  
  176.    *  Lots more.  Really.
  177.  
  178.  
  179. 1.2   Warnings, caveats, CYA.
  180.  
  181.    UPL's strengths are flexibility and convenience.  You can do almost anything
  182. with it, but you obviously (or hopefully) won't be able to do it as well as
  183. with a special-purpose utility.  Also, like any programming language, you need
  184. a bit of programming skill to use it properly.  UPL will happily trash your
  185. entire user file beyond recognition if you ask it to.  In the interest of speed
  186. and efficiency, >>> UPL DOES NOT CREATE A BACKUP FILE <<< (except when purging
  187. deleted users).  Once again, thoroughly test all new programs on a backup copy
  188. of USER.BBS before installation.  Don't say I didn't warn you.
  189.  
  190.  
  191.  
  192.  
  193. 1.3   Theory of Operation.
  194.  
  195.    A UPL program is a sequence of UPL commands which is executed against each
  196. record in your USER.BBS file.  In other words, all UPL programs are considerd
  197. to be inside a loop which says:
  198.  
  199.       FOR USERNUM=0 TO LASTUSER
  200.         <<< Your program >>>
  201.       NEXT USERNUM
  202.  
  203.    There are special commands provided which allow you to branch around within
  204. your program, proceed to the next user, proceed to the next program, abort
  205. everything, chain to another command file, etc.  There are commands provided to
  206. let you test or set any of the data in a user's record, perform simple
  207. calculations, and print output to the screen or to a file.  There's even a DOS
  208. shell command to let you run other utilities from within a UPL program.
  209.  
  210.    The simplest UPL program would be something like:
  211.  
  212.       SET @FILEAREA 1
  213.  
  214. which simply sets every user's 'last file area accessed' pointer to 1.  This is
  215. handy when you've rearranged your file areas (again) and don't want any of your
  216. users to pop out into hyperspace when they go to the file section.  A slightly
  217. more complex program could be like:
  218.  
  219.       IfGT @Downloads 1000
  220.         IfLT @ULRatio 5
  221.           Print '@name is a leech:'
  222.           Print '  Uploads=@uploadsKB, Downloads=@downloadsKB, Ratio=@ulratio%'
  223.           Set @Priv @Disgraced
  224.         Else
  225.           IfGT @ULRatio 25
  226.             Print '@name is wonderful.'
  227.             Set @Priv @Privil
  228.           EndIf
  229.         EndIf
  230.       EndIf
  231.  
  232. which would set any users who've downloaded more than a megabyte (1000K) and
  233. uploaded less than 5% to Disgraced, and anyone who's uploaded more than 25% to
  234. Privil.  Other example programs were (hopefully) included with the software,
  235. and you've probably already looked at them by now, so you should be getting the
  236. idea.
  237.  
  238.  
  239.  
  240.  
  241. 2.0   Language Syntax
  242. ---------------------
  243.  
  244. 2.1   Invocation.
  245.  
  246.    You execute a UPL program with the following command:
  247.  
  248.       UPL[/[B][+][$][#]] commandfile [argument1..argument9]
  249.  
  250.    'commandfile' is the name of a plain ASCII text file which contains UPL
  251. commands to be executed.  If no period is found in the name, the suffix '.UPL'
  252. will be assumed.  If the file is not in the current directory, your PATH will
  253. be searched for it.
  254.  
  255.    '[argument1..argument9]' represents up to 9 command line arguments which may
  256. be passed to the UPL program.  Blanks and tabs are delimiters.  If you wish an
  257. argument to contain embedded blanks or tabs, the argument must be delimited
  258. with single or double quotation marks.  To specify a null argument, use "".
  259. Arguments which are not given will be considered null ("") if referenced by the
  260. UPL program.  All arguments are shifted to upper-case before use.
  261.  
  262.    'B', '+', '$', and '#' are flags.  They may be specified in any combination
  263. or sequence, such as 'UPL/B#+$' or 'UPL/$#'.  Each flag enables a particular
  264. function, as follows:
  265.  
  266.       'B' enables Batch mode.  If this flag is not specified, any fatal errors
  267.           encountered while running your program will cause UPL to print a text
  268.           error message and pause for your acknowledgement.  If Batch mode is
  269.           specified, UPL will print an error number and die without waiting for
  270.           operator input. This allows UPL to be run more safely from unattended
  271.           batch files.  Upper and lower case are both accepted.
  272.  
  273.       '+' enables user record number trace mode.  This will cause UPL to print
  274.           a trace message as it processes each user record.  This lets you see
  275.           UPL's progress through your user data file.
  276.  
  277.       '$' enables source file trace mode.  This will cause UPL to display each
  278.           line of source code from the command file as it is executed.  This
  279.           allows you to trace the execution of your command files.
  280.  
  281.       '#' enables expression trace mode.  This will cause UPL to display each
  282.           command which accepts arguments AFTER the arguments have been
  283.           completely evaluated.  This is useful when debugging programs which
  284.           use complex expressions.
  285.  
  286.  
  287.  
  288.  
  289. 2.2   Command File Format.
  290.  
  291. 2.2.1   Statements.
  292.  
  293.    UPL commands are entered one per line.  Commands may have up to two
  294. arguments.  Spaces and tabs are used as delimiters.  If embedded spaces or tabs
  295. are required within an argument, the argument must be delimited with single or
  296. double quotation marks.  To include quotation marks within an argument, you
  297. must delimit it with the other kind of quotes.  Each command has a fixed number
  298. of arguments; any extra arguments on the line are completely ignored.  This
  299. allows inline comments to follow the command.  If an insufficient number of
  300. arguments are specified, the missing arguments will be considered null ("").
  301. Leading spaces and tabs are ignored, allowing you to indent as desired.  Upper
  302. and lower case may be mixed freely.
  303.  
  304. 2.2.2   Labels.
  305.  
  306.    A label may be any string expression whose rightmost character is ":".  It
  307. must be the first expression on the line.  Upper and lower case are not
  308. significant, as all labels are shifted to upper-case before parsing.  Any extra
  309. arguments after the label are treated as comments and ignored.  A label may be
  310. any number of characters, and can even have blanks and tabs in it if you feel
  311. like using quotes.  It's your program; I don't have to be able to read it.
  312.  
  313. 2.2.3   Comments, blank lines, etc.
  314.  
  315.    Any text after the expected number of arguments for a command is treated as
  316. a comment and ignored.  Lines which contain only blanks and tabs, or which
  317. contain nothing at all, are ignored.  Any line whose first non-blank-non-tab
  318. character is also non-alphabetic ('A'-'Z' or 'a'-'z'), is also considered a
  319. comment and ignored.  If you have source code trace mode on ('/$'), the entire
  320. source code line will be displayed verbatim as it is executed.  This allows you
  321. to place inline comments on your commands and see those comments in your trace
  322. output.
  323.  
  324. 2.2.4   Multiple programs per command file.
  325.  
  326.    A single command file may contain any number of programs.  Each program will
  327. be executed in sequence until the end of file is encountered.  Each program is
  328. separated from the next by the RUN command.  User variables are carried over
  329. from one program to the next; in all other respects, each program acts as if it
  330. were the only one in the file.  Most especially, labels are only recognized
  331. within the program they are defined in.  In other words, you can't GOTO one
  332. program from another.  In order to change from one program to another you must
  333. proceed through the command file to that point, or use the CHAIN command to
  334. invoke another command file.  You can also use the CHAIN command to re-invoke
  335. the current command file, but you'd better have code in place which decides to
  336. quit doing this eventually (unless you're fond of infinite loops).
  337.  
  338.  
  339.  
  340.  
  341. 3.0   Language Components
  342. -------------------------
  343.  
  344. 3.1   Constants.
  345.  
  346.    A constant is the most basic part of an expression.  It is either some text
  347. which you've entered yourself, or a predefined value such as @TWIT, or any
  348. combination of the two.  The following predefined constants are available:
  349.  
  350.      Privilege Levels:          Help Levels:          Command Line Arguments:
  351.         @TWIT       -2             @EXPERT  2            @ARG0 through @ARG9
  352.         @DISGRACED   0             @REGULAR 4
  353.         @NORMAL      2             @NOVICE  6
  354.         @PRIVIL      4
  355.         @PRIVEL      4          Miscellaneous:
  356.         @EXTRA       6             @OFF     0
  357.         @ASSTSYSOP   8             @ON      1
  358.         @SYSOP      10             @DATE    current date
  359.         @HIDDEN     11             @TIME    current time
  360.  
  361.    When UPL is evaluating an expression, it simply substitutes the proper value
  362. in place of any predefined constants it encounters.  @ARG0 will always be the
  363. name of the currently executing command file; the other @ARG values will be as
  364. given when UPL was run.
  365.  
  366.  
  367.  
  368. 3.2   Variables.
  369.  
  370.    A variable is like a constant, except that its value changes from one user
  371. record to the next.  Variables may also be changed by your program, and the
  372. user data file will be updated accordingly.  There are also 10 scratchpad
  373. variables available for your own use; they don't have any relation to the user
  374. data, but are instead used for loop counting, doing math, etc.  The following
  375. variables are available:
  376.  
  377.       USER.BBS User Data Record:
  378.          @NAME          String      User's first and last names
  379.          @CITY          String      City and state
  380.          @DELFLG2       Bit         Marks deleted records for REMSYSOP
  381.          @MRA0 - @MRA9  Integer     Last Message Read Area numbers
  382.          @MRC0 - @MRC9  Integer     Last Message Read message counters
  383.          @PASSWORD      String      User's password (aka PWD)
  384.          @CALLS         Integer     Number of times user has called (aka TIMES)
  385.          @HELP          Integer     User's current help setting
  386.          @TABS          Integer     0=translate tabs to spaces on output
  387.          @NULLS         Integer     Number of nulls to send after CR
  388.          @MSGAREA       Integer     Last message area visited (aka MSG)
  389.          @MOREWORD      Integer     Word containing various flag bits
  390.          @MOREBIT0 thru Bit         Individual bits in MOREWORD; Bit 0=least
  391.          @MOREBITF                    sig. (1), Bit F=most sig. (32768)
  392.          @MORE          Bit         Set = Use MORE? prompts     (@FLAGBITF)
  393.          @ANSI          Bit         Set = Use ANSI graphics     (@FLAGBITE)
  394.          @KLUDGE        Bit         Set = Been on Opus before   (@FLAGBITD)
  395.          @FORMFEED      Bit         Set = Perform screen clears (@FLAGBITC)
  396.          @PRIV          Integer     User's privilege level
  397.          @LASTCALL      String      Date and time of last call (aka LDATE)
  398.          @OLTODAY       Integer     Time online so far today (aka TIME)
  399.          @FLAGWORD      Integer     Word containing various bit flags
  400.          @FLAGBIT0 thru Bit         Individual bits in FLAGWORD; Bit 0=least
  401.          @FLAGBITF                    sig. (1), Bit F=most sig. (32768)
  402.          @DELFLG1       Bit         Marks deleted records for SYSOP207 & others
  403.          @UPLOADS       Unsigned    Total KB uploaded by this user   (aka UPLD)
  404.          @DOWNLOADS     Unsigned    Total KB downloaded by this user     (DNLD)
  405.          @DLTODAY       Integer     (downloads-uploads) performed today (DNLDL)
  406.          @FILEAREA      Integer     Last file area visited (aka FILES)
  407.          @WIDTH         Byte        Width of user's screen
  408.          @LENGTH        Byte        Length of user's screen
  409.          @CREDIT        Integer     Netmail message credit, in cents
  410.          @DEBIT         Integer     Pending netmail message debt, in cents
  411.  
  412.       Variables Derived from the User Record (can't be changed directly):
  413.          @DAYSAGO       Integer     Number of days since last call
  414.          @ULRATIO       Unsigned    UPLOADS/DOWNLOADS, given as a percentage
  415.          @USERNUM       Integer     User record number being processed (from 0)
  416.  
  417.       Variables for you to play with:
  418.          @VAR0 - @VAR9  String      Use for whatever you want
  419.  
  420.    Variables have a specific data type (String, Integer, etc.).  UPL will
  421. attempt to convert data as neccessary in order to perform your commands, but
  422. some operations (like SET @UPLOADS "FROG") are obviously impossible and will
  423. get you a fatal error.  When setting Bit variables, any non-zero value will be
  424. treated as 1.  When setting Byte variables, only the least-significant byte of
  425. the new value will be used.  Note that the scratchpad variables are described
  426. as Strings.  They may contain whatever you want, and UPL will attempt to figure
  427. them out by context.
  428.  
  429.  
  430.  
  431.  
  432. 3.3   Expressions.
  433.  
  434.    An expression is any combination of literal text, constants, and variables.
  435. UPL will substitute the proper values for any constants or variables found
  436. before using an expression.  Substitutions are made iteratively from left to
  437. right until no more constants or variables can be found.  For example:
  438.  
  439.       "@name is a great guy."  might equal "Rick Huebner is a great guy."
  440.       "SET @PRIV @TWIT" would be executed as "SET @PRIV -2"
  441.  
  442. but here's a better one:
  443.  
  444.       SET @VAR0 9
  445.       SET @VAR3 "TEXT STRING"
  446.       SET @VAR9 3
  447.       PRINT Complex@VAR@VAR@VAR0Expression
  448.  
  449. would print:   "ComplexTEXT STRINGExpression"  because "@VAR@VAR@VAR0" would be
  450. translated first into "@VAR@VAR9", and then into "@VAR3", and finally into
  451. "TEXT STRING".  Note that the "@" is only significant if it directly precedes a
  452. recognizable variable or constant name; otherwise, it's just text.  Also,
  453. remember that labels are just another kind of string; you can do some really
  454. neat things with commands like "GOTO Case@VAR0" if you program it properly.
  455. This is left as an exercise for the reader.
  456.  
  457.    There are two special-purpose kinds of expressions used by certain UPL
  458. commands: Filename and Textline.  If a Filename expression does not contain a
  459. period, an extension of ".GBS" or ".BBS" will be assumed, according to the
  460. user's @ANSI setting and which files exist.  The selection logic is like this:
  461.  
  462.       If user's ANSI setting is off then
  463.         Append ".BBS" to filename
  464.       Else
  465.         If filename.GBS does not exist and filename.BBS does exist,
  466.           Append ".BBS" to filename
  467.         Else
  468.           Append ".GBS" to filename
  469.         EndIf
  470.       EndIf
  471.  
  472.    This allows you to write to or copy from files which properly correspond to
  473. the user's ANSI setting.  Note that since the ANSI bit should never be set on a
  474. Fido board, Fido sysops may consider Filename expressions to simply have a
  475. default extension of ".BBS".
  476.  
  477.    The other kind of special-purpose expression is the Textline.  The PRINT and
  478. FPRINT commands use this expression type.  It's simply a generic string
  479. expression with 2 extra format commands recognized.  Any occurrance of "$nn",
  480. where "nn" is a valid 2-character hexadecimal number, will be replaced by a
  481. byte with that ASCII value.  Also, if the string ends with a semicolon (;), the
  482. carriage-return at the end of the string will be suppressed.  If you wish the
  483. semicolon at the end of the line to print out, use "Text; ".  If you wish to
  484. both print a semicolon at the end AND suppress the carriage-return, use
  485. "Text;;".  Got all that?
  486.  
  487.  
  488.  
  489.  
  490. 3.4   Commands.
  491.  
  492. 3.4.1   ABORT
  493.  
  494.    Causes UPL to stop processing immediately and return to DOS.  This command
  495. differs from END in that the entire command file is aborted, not just the
  496. currently executing program.
  497.  
  498.    See also:  CHAIN, END, NEXTUSER, RUN
  499.  
  500.  
  501. 3.4.2   ADD variable numerical_expression
  502.  
  503.    Adds the value of 'numerical_expression' to 'variable'.  If
  504. 'numerical_expression' is null (""), its value is considered to be 0, and
  505. nothing happens.
  506.  
  507.    Examples:  ADD @VAR0 1
  508.               ADD @CREDIT @ARG2
  509.  
  510.    See also:  SUB, MUL, DIV, MOD, SET
  511.  
  512.  
  513. 3.4.3   CHAIN string_expression
  514.  
  515.    Transfers control to the command file named in 'string_expression'.  Control
  516. will not return to the current command file.  'string_expression' has exactly
  517. the same format as the DOS command line.
  518.  
  519.    Examples:  CHAIN "/$ othrfile argone 'arg two' arg3"
  520.               CHAIN "@Arg0 @Arg1 NewArg2 @Arg3"
  521.  
  522.    See also:  ABORT, END, NEXTUSER, RUN
  523.  
  524.  
  525. 3.4.4   CWKILL
  526.  
  527.    Deletes all Opus custom welcome messages from the current directory.  A
  528. custom welcome message is defined as "n.BBS", where 'n' is any valid decimal
  529. integer value.   This is used to delete outdated messages before creating new
  530. ones.  It's a good idea to immediately follow this command with END, since it's
  531. silly (and slow) to delete all the old messages once for every user in your
  532. user list.
  533.  
  534.    See also:  DOS, FAPPEND, FPRINT, MQFLUSH, MQMSG
  535.  
  536.  
  537. 3.4.5   DIV variable numerical_expression
  538.  
  539.    Divides the value in 'variable' by the value of 'numerical_expression'.
  540. If 'numerical_expression' is 0 or null ("") a fatal error will occur.  The
  541. result will have any fractional part truncated.  Use MOD to determine the
  542. remainder if neccessary.
  543.  
  544.    Examples:  DIV @VAR0 10
  545.  
  546.    See also:  ADD, SUB, MUL, MOD, SET
  547.  
  548.  
  549.  
  550.  
  551. 3.4.6   DOS string_expression
  552.  
  553.    Bring up a child copy of COMMAND.COM to execute the command in
  554. 'string_expression'.  If 'string_expression' is null ("") or missing (same
  555. thing), the new COMMAND.COM will wait for you to type in commands at your
  556. keyboard, and control will not pass back to UPL until you type the "EXIT"
  557. command.  This command requires a lot of memory, the exact amout depending on
  558. just what you try to run.
  559.  
  560.    Examples:  DOS
  561.               DOS "renum -n 0 150 @VAR0 -r @VAR0"
  562.  
  563.    See also:  CWKILL, FAPPEND, FPRINT, MQFLUSH, MQMSG
  564.  
  565.  
  566. 3.4.7   END
  567.  
  568.    Halts the execution of the current program, and causes UPL to continue
  569. forward to the next program in the command file (if any).  UPL pretends like it
  570. has all of a sudden finished processing the last user in your data file.
  571.  
  572.    See also:  ABORT, CHAIN, NEXTUSER, RUN
  573.  
  574.  
  575. 3.4.8   FAPPEND filename_expression1 filename_expression2
  576.  
  577.    Copies the contents of the file named by 'filename_expression2' onto the end
  578. of the file named by 'filename_expression1'.  The file named by
  579. 'filename_expression2' must already exist or a fatal error will occur.  If the
  580. file named by 'filename_expression1' does not exist, it is created.  If a
  581. filename extension is not present, '.GBS' or '.BBS' will be assumed as
  582. appropriate.  See section 3.3 for details.
  583.  
  584.    Examples:  FAPPEND @usernum.bbs twit (copies TWIT.<G B>BS to the user's
  585.                                          custom welcome message file)
  586.  
  587.    See also:  CWKILL, DOS, FPRINT, MQFLUSH, MQMSG
  588.  
  589.  
  590. 3.4.9   FPRINT filename_expression textline_expression
  591.  
  592.    Appends the text in 'textline_expression' to the end of the file named by
  593. 'filename_expression'.  If the file named by 'filename_expression' does not
  594. already exist, is is created.  See section 3.3 for details on filename and
  595. textline expressions.
  596.  
  597.    Examples:  FPRINT purge.rpt @name$09@lastcall$09@daysago
  598.               FPRINT @usernum.bbs "$0FCc:\opus\misc\hell"
  599.  
  600.    See also:  CWKILL, DOS, FAPPEND, MQFLUSH, MQMSG
  601.  
  602.  
  603.  
  604.  
  605. 3.4.10   GOTO label_expression
  606.  
  607.    Jumps to the next command line after the line which contains
  608. 'label_expression'.  The colon (":") on the end of the label should not be
  609. given in the GOTO command.  See section 2.2.2 for label syntax details.
  610.  
  611.    Examples:  GOTO TopOfLoop
  612.               GOTO Priv@PRIV  (will jump to 'Priv-2', 'Priv0', 'Priv2', etc.)
  613.               GOTO Case@VAR0
  614.  
  615.    See also:  IF
  616.  
  617.  
  618. 3.4.11   IF
  619.  
  620.    Compares two expressions to each other, and decides where to go based on the
  621. results.  The full structure is:
  622.  
  623.       IFxx expression1 expression2
  624.         <<< other commands >>>
  625.       [ELSE]
  626.         [ <<< other commands>>> ]
  627.       ENDIF
  628.  
  629. 'xx' may be any one of 'EQ', 'NE', 'LT', 'LE', 'GT', or 'GE'.  If the condition
  630. is true, the first set of commands will be executed.  If the condition is
  631. false, the second set of commands will be executed (if present).  The two
  632. expressions to be compared may be of any type.  If both expressions can be
  633. converted to a 16-bit integer, the comparison will be made arithmetically; if
  634. one or the other expression is not numeric, the comparison will be made
  635. alphabetically.  The comparison is performed in upper-case, so the case of the
  636. two expressions is not significant.  Comparison with unsigned variables
  637. (@UPLOADS, @DOWNLOADS, @ULRATIO) is a special case; the values will be
  638. converted to 5-digit 0-padded strings and compared alphabetically, so as to
  639. avoid problems like 60000 being less than 1.  Also, if @DOWNLOADS equals 0,
  640. @ULRATIO will equal 65535, which is as close to infinity as you can get in 16
  641. bits. If you have expression trace mode ("/#") on, you can tell whether the
  642. comparison is being made arithmetically or alphabetically by looking for
  643. quotation marks around the expressions.
  644.  
  645.    Examples:  Ifeq @name 'rick huebner'
  646.                 set @priv @extra
  647.               endif
  648.  
  649.               IfLT @var0 @var1 Then  ('Then' is a comment, but it looks good)
  650.                 Print "@var0 is less than @var1."
  651.               Else
  652.                 Print "@var0 is not less than @var1."
  653.               Endif
  654.  
  655.    See also:  GOTO
  656.  
  657.  
  658.  
  659. 3.4.12   MOD variable numerical_expression
  660.  
  661.    Sets 'variable' equal to the remainder of 'variable' divided by
  662. 'numerical_expression.'  For example, if 'variable' contained 10, and
  663. 'numerical_expression' worked out to 3, 'variable' would end up being set to 1
  664. (10 mod 3 = 1).  If 'numerical_expression' is 0 or null ("") a fatal error will
  665. occur.
  666.  
  667.    Examples:  MOD @VAR0 10
  668.  
  669.    See also:  ADD, SUB, MUL, DIV, SET
  670.  
  671.  
  672. 3.4.13   MQFLUSH
  673.  
  674.    This is a special-purpose command designed to work with MQMSG.  It clears
  675. the flag which MQMSG uses to tell if it has already run POLE_MQ or not, forcing
  676. MQMSG to re-execute POLE_MQ on the next iteration.  Frankly, I'm not sure if
  677. there's a good application for this or not, but I threw it in for completeness'
  678. sake.  See the description of MQMSG below for details.
  679.  
  680.    See also:  CWKILL, DOS, FAPPEND, FPRINT, MQMSG
  681.  
  682.  
  683. 3.4.14   MQMSG string_expression
  684.  
  685.    This is a very special-purpose command.  It executes POLE_MQ with the
  686. arguments given in 'string_expression', loads the output report into memory,
  687. and then creates/appends to an Opus custom welcome message those lines showing
  688. that individual user's waiting mail.  This way, each user gets a quick one or
  689. two line message showing only their waiting messages, rather than everybody
  690. having to read a full-page report showing everybody's waiting messages. POLE_MQ
  691. is only actually run on the first use of this command; after that, the output
  692. file has been loaded into memory and is simply scanned for each user. Use the
  693. MQFLUSH command if you wish to force POLE_MQ to be run again once it has
  694. executed.  If the current user was not reported to have waiting mail by
  695. POLE_MQ, this command does nothing.  POLE_MQ must be able to be found via your
  696. DOS PATH for this command to work.  Also, like any command which runs a second
  697. program, it requires a lot of memory.
  698.  
  699.    The special reserved variable @MAIL is set by this command to reflect the
  700. number of lines of text which were appended to the user's custom welcome
  701. message.  This can be used in various ways:
  702.  
  703.       mqmsg "1 2 3 4 5"
  704.       ifeq @mail 0
  705.         fprint @usernum.bbs "You had no mail waiting at @time on @date."
  706.       else
  707.         ifgt @mail 2
  708.           fprint @usernum.bbs "You've got a lot of mail waiting.  It must"
  709.           fprint @usernum.bbs "be nice to be so popular.  Please delete some"
  710.           fprint @usernum.bbs "after reading."
  711.         endif
  712.       endif
  713.  
  714. I don't recommend leaving custom welcome messages to users without waiting mail
  715. unless you've got disk space to burn, or a very small cluster size.
  716.  
  717.    Examples:  MQMSG "1 2 3 4 5"
  718.  
  719.    See also:  CWKILL, DOS, FAPPEND, FPRINT, MQFLUSH
  720.  
  721.  
  722.  
  723. 3.4.15   MUL variable numerical_expression
  724.  
  725.    Multiplies the value in 'variable' by the value of 'numerical_expression'.
  726. If 'numerical_expression' is null (""), its value is considered to be 0, and
  727. 'variable' gets set to 0.
  728.  
  729.    Examples:  MUL @VAR0 10
  730.  
  731.    See also:  ADD, SUB, DIV, MOD, SET
  732.  
  733.  
  734. 3.4.16   NEXTUSER
  735.  
  736.    Causes UPL to immediately proceed to processing the next user in the
  737. USER.BBS file.  This will also restart the current program from the top.  If
  738. you remember that your UPL program is assumed to be within a FOR USERNUM=0 TO
  739. LASTUSER loop, you can see that NEXTUSER simply jumps to the NEXT USERNUM
  740. statement which is assumed to follow your program.  An identical effect could
  741. be achieved by placing a label at the end of your program and jumping there
  742. with GOTO, but NEXTUSER is faster.
  743.  
  744.    See also:  ABORT, CHAIN, END, RUN
  745.  
  746.  
  747. 3.4.17   RUN
  748.  
  749.    Causes UPL to stop reading and parsing commands, and to execute the program
  750. which it has read so far.  This command allows you to have more than one
  751. executable UPL program within a single command file.  Once this program has
  752. finished, UPL will resume reading and parsing commands from the command file
  753. starting with the line after the RUN command.  Each program separated by a RUN
  754. command is a totally separate entity; the only communication possible between
  755. them is via the user-defined variables (@VAR0 - @VAR9), which maintain their
  756. current values from one program to the next.
  757.  
  758.    See also:  ABORT, CHAIN, END, NEXTUSER
  759.  
  760.  
  761. 3.4.18   SET variable expression
  762.  
  763.    Sets the contents of 'variable' to the value of 'expression'.  UPL will
  764. attempt to convert the data type of 'expression' to that of 'variable' if
  765. possible.  A string variable may be set to anything, and will be truncated if
  766. too long.  An integer may be set to any value from -32768 to 32767.  An
  767. unsigned variable may be set to any value from 0 to 65535.  A byte may be set
  768. to any numeric value, but only the least significant 8 bits of the expression
  769. will be used (0-255).  A bit may be set to any numeric value, but any value
  770. other than 0 will be treated as 1.  If you attempt to do something silly like
  771. set an integer variable to an alphabetic string, a fatal error will be
  772. generated.  The special user-data derived variables @DAYSAGO, @ULRATIO, and
  773. @USERNUM can not be directly set (but you could set @LASTCALL, or @DOWNLOADS,
  774. or whatever).
  775.  
  776.    Examples:  SET @PRIV @TWIT
  777.               SET @VAR0 "This is a text string"
  778.               SET @VAR0 12
  779.               SET @PASSWORD ""
  780.  
  781.    See also:  ADD, SUB, MUL, DIV, MOD
  782.  
  783.  
  784.  
  785.  
  786. 3.4.19   SUB variable numeric_expression
  787.  
  788.    Subtracts the value of 'numerical_expression' from 'variable'.  If
  789. 'numerical_expression' is null (""), its value is considered to be 0, and
  790. nothing happens.
  791.  
  792.    Examples:  SUB @VAR0 1
  793.               SUB @CREDIT @DEBIT  (hopefully followed by SET @DEBIT 0)
  794.  
  795.    See also:  ADD, MUL, DIV, MOD, SET
  796.  
  797.  
  798. 3.4.20   PRINT textline_expression
  799.  
  800.    Prints the value of 'textline_expression' on the console.  Embedded control
  801. codes and carriage-return suppression are available; see section 3.3 for
  802. details on textline expressions.
  803.  
  804.    Examples:  Print "Are you as tired of reading this as I am of typing it?"
  805.               print "Last read #@MRC@VAR0 in area @MRA@VAR0."
  806.  
  807.  
  808. 3.4.21   PURGE
  809.  
  810.    This command will read through your USER.BBS file and remove any user data
  811. records which have been flagged as deleted.  There are two deletion flags
  812. supported.  The first one, @DELFLG1, is the least significant bit of @FLAGWORD
  813. (@FLAGBIT0).  This bit is used by SYSOP207 and some other sysop maintainence
  814. programs as a flag to remember which records have been marked for deletion. The
  815. second one, @DELFLG2, is stored as a text string within the field reserved for
  816. the user's city and state.  This is the method used by REMSYSOP.  Note that
  817. although the flag is stored in the record as a text string, UPL treats @DELFLG2
  818. as a bit variable.  If you set @DELFLG2 to 0, the text string will be nulled
  819. out; if you set @DELFLG2 to 1, the text string will be inserted.
  820.  
  821.    UPL will rename your current USER.BBS file as USER.BAK before doing the
  822. purge.  Then your old user data is read, and each record is written to either
  823. the new USER.BBS file, or to USER.OLD.  USER.BAK and USER.OLD are deleted if
  824. neccessary before purging. When the purge is completed, the PURGE command will
  825. execute an implied END command, since UPL no longer knows what your USER.BBS
  826. file looks like.
  827.  
  828.    See also:  END
  829.  
  830.  
  831.  
  832. 4.0   Programming Considerations
  833. --------------------------------
  834.  
  835. 4.1   Limitations.
  836.  
  837.    There are several arbitrary limits to a UPL program.  I have tried to set
  838. these higher than anyone should ever need:
  839.  
  840.       Maximum number of executable commands per program:  1024
  841.         (ELSE and ENDIF also count, as they have tokens
  842.          kept there for trace mode outputs)
  843.  
  844.       Maximum nesting depth for IF statements:             100
  845.  
  846.       Maximum number of labels per program:                100
  847.  
  848.       Maximum number of expressions per program:           900+ (depends)
  849.  
  850. When I say 'per program,' I mean per each individually executed program within
  851. a command file, NOT per command file as a whole.  If you manage to run into any
  852. of these limits, let me know; I'd like to know what you're doing to my poor
  853. interpreter while I'm not watching.
  854.  
  855.  
  856. 4.2   Efficiency considerations.
  857.  
  858.    UPL is a one-pass tokenizing interpreter.  It reads and tokenizes commands
  859. from the command file until either a RUN command or the end of file is
  860. encountered.  It then opens your USER.BBS file and performs the tokenized
  861. commands in a loop for each record in your user data file.
  862.  
  863.    Constants are evaluated during the tokenization process, and so are
  864. basically free.  Using a constant is exactly like typing in that literal text
  865. manually.  Variables, on the other hand, are evaluated as the commands which
  866. use them are executed, every time they are executed.  A complex expression can
  867. require quite a bit of time to evaluate.  This is the easiest way to slow down
  868. your UPL programs.  Also, GOTO's are slower than ELSE's, so try to write
  869. reasonably structured top-down code if possible.  It's quite possible for more
  870. code to be faster than less code... for example:
  871.  
  872.     set @var0 0
  873.  
  874.     NextArea:
  875.     ifeq @mra@var0 @arg1
  876.       set @mra@var0 @arg2
  877.       print 'Changed area @arg1 to area @arg2 for @name.'
  878.     else
  879.       add @var0 1
  880.       ifle @var0 9
  881.         goto NextArea
  882.       endif
  883.     endif
  884.  
  885.    This is a slick little routine to change every occurrence of a given last
  886. message read area (@ARG1) to a new area number (@ARG2).  This would be used if
  887. you move a message area to somewhere else, and feel like being nice to your
  888. users.  Note the cute way in which the 10 different area numbers are checked in
  889. a loop by incrementing @VAR0.  However, the following program does the same
  890. thing, faster, since it doesn't have to evaluate that cute little '@MRA@VAR0'
  891. trick, or do that GOTO:
  892.  
  893.  
  894.  
  895.  
  896. ifeq @mra0 @arg1
  897.   set @mra0 @arg2
  898.   print 'Changed area @arg1 to area @arg2 for @name.'
  899.   nextuser
  900. else
  901.   ifeq @mra1 @arg1
  902.     set @mra1 @arg2
  903.     print 'Changed area @arg1 to area @arg2 for @name.'
  904.     nextuser
  905.   else
  906.     ifeq @mra2 @arg1
  907.       set @mra2 @arg2
  908.       print 'Changed area @arg1 to area @arg2 for @name.'
  909.       nextuser
  910.     else
  911.       ifeq @mra3 @arg1
  912.         set @mra3 @arg2
  913.         print 'Changed area @arg1 to area @arg2 for @name.'
  914.         nextuser
  915.       else
  916.         ifeq @mra4 @arg1
  917.           set @mra4 @arg2
  918.           print 'Changed area @arg1 to area @arg2 for @name.'
  919.           nextuser
  920.         else
  921.           ifeq @mra5 @arg1
  922.             set @mra5 @arg2
  923.             print 'Changed area @arg1 to area @arg2 for @name.'
  924.             nextuser
  925.           else
  926.             ifeq @mra6 @arg1
  927.               set @mra6 @arg2
  928.               print 'Changed area @arg1 to area @arg2 for @name.'
  929.               nextuser
  930.             else
  931.               ifeq @mra7 @arg1
  932.                 set @mra7 @arg2
  933.                 print 'Changed area @arg1 to area @arg2 for @name.'
  934.                 nextuser
  935.               else
  936.                 ifeq @mra8 @arg1
  937.                   set @mra8 @arg2
  938.                   print 'Changed area @arg1 to area @arg2 for @name.'
  939.                   nextuser
  940.                 else
  941.                   ifeq @mra9 @arg1
  942.                     set @mra9 @arg2
  943.                     print 'Changed area @arg1 to area @arg2 for @name.'
  944.                   endif
  945.                   nextuser
  946.                 endif
  947.               endif
  948.             endif
  949.           endif
  950.         endif
  951.       endif
  952.     endif
  953.   endif
  954. endif
  955.  
  956.  
  957.  
  958.  
  959.    Note that although not strictly neccessary, the NEXTUSER commands speed
  960. things up a little bit by saving UPL the trouble of falling through all those
  961. ELSE's and ENDIFs (Yes, ELSE and ENDIF do take a teeny bit of time, since UPL
  962. has to check if you've got trace mode on, but not as much as a GOTO).
  963.  
  964.    One last word on efficiency... I'll admit right now that UPL was written in
  965. QuickBasic, not 'C'.  I know full well that if I had written it in C it would
  966. be half the size and go twice as fast.  However, since I don't own a commercial
  967. quality C compiler and source level debugger, it would have taken me twice as
  968. long to write, and would probably never have gotten finished.  Maybe I'll redo
  969. it once Turbo C gets released, but don't hold your breath.
  970.  
  971.  
  972.  
  973.  
  974. 5.0   Postscript
  975. ----------------
  976.  
  977. 5.1   Future Enhancements.
  978.  
  979.    The only future enhancement which I'm definately going to make is support of
  980. whatever new Opus user data structure Wynn finally settles on.  As a matter of
  981. fact, the next major rev of UPL will probably not be usable on Fido systems
  982. anymore at all (but they can keep using version 1).
  983.  
  984.    I will make an effort to fix any bugs which are discovered, and I'm willing
  985. to listen to ideas for enhancements.  I'm not promising to implement them all,
  986. just to listen to them.
  987.  
  988.  
  989. 5.2   Bug Reports, etc.
  990.  
  991.    Send any bug reports or enhancement requests to me at my board,
  992. FidoNet/Matrix node 14/614 (402-291-8053 3/12/2400 bps, 24 hrs.).  Constructive
  993. criticism, heaps of praise, expensive 'C' compilers, and lucrative job offers
  994. will be cheerfully accepted.  Snide comments and hate mail will convince me
  995. never to bother writing utilities for anyone else again.
  996.  
  997.    A copy of the latest version of this program will always be available on my
  998. board for download by first-time callers.  I don't run SEADog, so don't bother
  999. file requesting it.
  1000.  
  1001.  
  1002.  
  1003.                                       END
  1004.  
  1005.